﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Navigation;
using LASGui.Classes;
using LASGui.MainService;

namespace LASGui.Views
{
    public partial class Cuentas
    {
        private readonly AuthenticatedUser _authenticatedUserManager = AuthenticatedUser.Instance;
        private Account _currentAccount = new Account();
        private readonly List<String> _currencyList = new List<string>();
        private CustomChildWindow _dialogWindow;

        #region Navegacion
        /// <summary>
        /// Evento de navegacion que se dispara al terminar la navegación a esta página.
        /// </summary>
        /// <param name="e"></param>
        protected override void OnNavigatedTo(NavigationEventArgs e)
        {
            if (_authenticatedUserManager.OnlineUser == null)
            {
                LogOff();
            }

            InitializeComponent();
            LoadCurrentAccountTree(0);
            MenuActivos.Background = new SolidColorBrush(GetColorFromHexString("FFC5D685"));

            foreach (var currency in _authenticatedUserManager.CompanyCurrency)
            {
                _currencyList.Add(currency.CurrencyName);
            }

            InputDetalleMoneda.ItemsSource = _currencyList;
            InputDetalleMoneda.SelectedIndex = 0;
            InputNuevaCuentaMoneda.ItemsSource = _currencyList;
            InputNuevaCuentaMoneda.SelectedIndex = 0;
        }

        /// <summary>
        /// Método que obliga al usuario a salir de su sesión si se presenta un error de conexión o si intenta accesar a un zona reestringida sin haberse autenticado primero.
        /// </summary>
        public void LogOff()
        {
            _authenticatedUserManager.OnlineUser = null;
            NavigationService.Navigate(new Uri("/Home", UriKind.Relative));
            var mainPage = ((App)Application.Current).Mainpage;
            mainPage.HideMainMenu();
        }
        #endregion

        #region Actualización de arboles
        /// <summary>
        /// Método que crea el árbol a partir de una cuenta hija dentro de un TreeViewItem padre
        /// </summary>
        /// <param name="toBeParent">Cuenta que será desglosada para determinar los hijos y los hijos de los hijos</param>
        /// <param name="parent">Componente visual Padre de la cuenta en cuestion, a la que se le agregará la cuenta nueva con sus hijos si es que tiene.</param>
        public void LoadAccountChildTree(Account toBeParent, TreeViewItem parent)
        {
            var toBeParentTree = new AccountTreeViewItem(toBeParent);
            toBeParentTree.Selected += ParentTreeSelected;
            parent.Items.Add(toBeParentTree);

            if (toBeParent.Children == null) return;

            foreach (var child in toBeParent.Children)
            {
                LoadAccountChildTree(child, toBeParentTree);
            }
        }

        /// <summary>
        /// Método que crea el árbol de una de las cuentas título dentro de el catálogo de cuentas.
        /// </summary>
        /// <param name="accountCatalogIndex">El index de dicha cuenta dentro del catálogo</param>
        public void LoadCurrentAccountTree(int accountCatalogIndex)
        {

            _currentAccount = _authenticatedUserManager.OnlineUser.Company.AccountCatalog.Accounts[accountCatalogIndex];
            LoadCurrentAccountInformation();
            var parentTree = new AccountTreeViewItem(_currentAccount);
            InputArbolCuentas.Items.Add(parentTree);
            parentTree.Selected += ParentTreeSelected;

            foreach (var child in _currentAccount.Children)
            {
                LoadAccountChildTree(child, parentTree);
            }
        }

        /// <summary>
        /// Evento que se dispara al cambiar la cuenta dentro del árbol de cuentas.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public void ParentTreeSelected(object sender, RoutedEventArgs e)
        {
            var selectedTreeViewItem = (AccountTreeViewItem)sender;
            _currentAccount = selectedTreeViewItem.Account;
            LoadCurrentAccountInformation();
        }
        #endregion

        #region Actualización información y control de input
        /// <summary>
        /// Carga la información de la cuenta seleccionada.
        /// </summary>
        public void LoadCurrentAccountInformation()
        {
            InputDetalleCodigo.Text = _currentAccount.AccountCode;
            InputDetalleNombre.Text = _currentAccount.AccountName;
            InputDetalleNombreExtranjero.Text = _currentAccount.ForeignName;

            if (_currentAccount.AccountCode[0] == '2' || _currentAccount.AccountCode[0] == '3' || _currentAccount.AccountCode[0] == '4' || _currentAccount.AccountCode[0] == '7')
            {
                InputDetalleSaldoLocal.Text = (_currentAccount.LocalBalance * -1).ToString("0.0000");
                InputDetalleSaldoSistema.Text = (_currentAccount.SystemBalance * -1).ToString("0.0000");
            }
            else
            {
                InputDetalleSaldoLocal.Text = _currentAccount.LocalBalance.ToString("0.0000");
                InputDetalleSaldoSistema.Text = _currentAccount.SystemBalance.ToString("0.0000");
            }

            InputNuevaCuentaTitulo.Text = _currentAccount.AccountCode + " " + _currentAccount.AccountName;
            InputNuevaCuentaCodigo.Text = _currentAccount.AccountCode + "-";
            InputDetalleMoneda.SelectedIndex = _currencyList.IndexOf(_currentAccount.Currency.CurrencyName);
            InputDetalleTipo.Text = _currentAccount.AccountType == "Titulo" ? "Cuenta Título" : _currentAccount.AccountType;


        }

        /// <summary>
        /// Método que limpia los campos despues de ingresar una nueva cuenta.
        /// </summary>
        public void Reset()
        {
            InputArbolCuentas.Items.Clear();
            LoadCurrentAccountTree(int.Parse(_currentAccount.AccountCode.Substring(0,1))-1);
            InputNuevaCuentaMoneda.SelectedIndex = 0;
            InputNuevaCuentaCodigo.Text = "";
            InputNuevaCuentaNombre.Text = "";
            InputNuevaCuentaNombreExtranjero.Text = "";
        }
        #endregion

        #region Mouse Events
        /// <summary>
        /// Evento que se dispara al cambiar de tipo de cuenta.
        /// </summary>
        private void ChangeCurrentAccountDisplay(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {

            //Elimina el color de los items en el menu
            foreach (var childBorder in Linea1.Children.Cast<Border>())
            {
                childBorder.Background = null;
            }
            foreach (var childBorder in Linea2.Children.Cast<Border>())
            {
                childBorder.Background = null;
            }
            foreach (var childBorder in Linea3.Children.Cast<Border>())
            {
                childBorder.Background = null;
            }

            //Cambia el color del item seleccionado
            var clickedBorder = (Border)sender;
            clickedBorder.Background = new SolidColorBrush(GetColorFromHexString("FFC5D685"));

            //Limpia el componente visual del arbol anterior
            InputArbolCuentas.Items.Clear();
            //Despliega el arbol nuevo segun el menu seleccionado
            if (sender == MenuActivos)
            {
                LoadCurrentAccountTree(0);
            }
            else if (sender == MenuPasivos)
            {
                LoadCurrentAccountTree(1);
            }
            else if (sender == MenuPatrimonio)
            {
                LoadCurrentAccountTree(2);
            }
            else if (sender == MenuIngresos)
            {
                LoadCurrentAccountTree(3);
            }
            else if (sender == MenuCostos)
            {
                LoadCurrentAccountTree(4);
            }
            else if (sender == MenuGastos)
            {
                LoadCurrentAccountTree(5);
            }
            else if (sender == MenuOtrosIngresos)
            {
                LoadCurrentAccountTree(6);
            }
            else if (sender == MenuOtrosGastos)
            {
                LoadCurrentAccountTree(7);
            }
        }

        /// <summary>
        /// Evento que se dispara al hacer click en el botón de crear una nueva cuenta
        /// </summary>
        private void AddAccount(object sender, RoutedEventArgs e)
        {
            var newAccount = new Account
                                 {
                                     AccountName = InputNuevaCuentaNombre.Text,
                                     AccountCode = InputNuevaCuentaCodigo.Text,
                                     ParentAccountId = _currentAccount.AccountId,
                                     ForeignName = InputNuevaCuentaNombreExtranjero.Text,
                                     Currency = _authenticatedUserManager.CompanyCurrency[InputNuevaCuentaMoneda.SelectedIndex],
                                     ParentAccount = _currentAccount,
                                     AccountCatalogId = _authenticatedUserManager.OnlineUser.Company.AccountCatalog.AccountCatalogId
                                 };
            InsertAccount(newAccount);
            _dialogWindow = new CustomChildWindow("Agregando la nueva cuenta...");
            _dialogWindow.Show();

        }

        /// <summary>
        /// Evento que se dispara al hacer click en el botón de modificar una cuenta
        /// </summary>
        private void ChangeAccountInformation(object sender, RoutedEventArgs e)
        {
            var account = new Account
            {
                AccountId = _currentAccount.AccountId,
                AccountName = InputDetalleNombre.Text,
                ForeignName = InputDetalleNombreExtranjero.Text,
                Currency = _authenticatedUserManager.CompanyCurrency[InputDetalleMoneda.SelectedIndex],
            };
            EditAccountInformation(account);
            _dialogWindow = new CustomChildWindow("Modificando la cuenta seleccionada...");
            _dialogWindow.Show();

        }

        /// <summary>
        /// Evento que permite borrar una cuenta al hacer clic en el botón de borrar
        /// </summary>
        private void EraseAccount(object sender, RoutedEventArgs e)
        {
            if (_currentAccount.AccountType == "Titulo")
            {
                _dialogWindow = new CustomChildWindow("Error al eliminar cuenta", "No se puede borrar la cuenta pues esta es una cuenta Título");
                _dialogWindow.Show();
                return;
            }
            if (_currentAccount.Level == 2)
            {
                _dialogWindow = new CustomChildWindow("Error al eliminar cuenta","No se puede borrar la cuenta pues es de funcionalidad del sistema");
                _dialogWindow.Show();
                return;
            }
            DeleteAccount(_currentAccount.AccountId);
            _dialogWindow = new CustomChildWindow("Borrando la cuenta seleccionada...");
            _dialogWindow.Show();
             
        }
        #endregion

        #region Webservice Calls
        /// <summary>
        /// Método que obtiene el catálogo de cuentas.
        /// </summary>
        public void GetAccountCatalog()
        {
            var client = new MainServiceSilverlightClient();
            client.GetAccountingCatalogCompleted += ClientGetAccountingCatalogCompleted;
            client.GetAccountingCatalogAsync(_authenticatedUserManager.OnlineUser.CompanyId);
        }

        /// <summary>
        /// Método que inserta una nueva cuenta
        /// </summary>
        /// <param name="newAccount"></param>
        public void InsertAccount(Account newAccount)
        {
            var client = new MainServiceSilverlightClient();
            client.InsertNewAccountCompleted += ClientInsertNewAccountCompleted;
            client.InsertNewAccountAsync(newAccount);
        }

        /// <summary>
        /// Método que edita una cuenta
        /// </summary>
        /// <param name="account"></param>
        public void EditAccountInformation(Account account)
        {
            var client = new MainServiceSilverlightClient();
            client.ChangeAccountInformationCompleted += ClientChangeAccountInformationCompleted;
            client.ChangeAccountInformationAsync(account);
        }


        /// <summary>
        /// Método que elimina una cuenta
        /// </summary>
        /// <param name="accountId"></param>
        public void DeleteAccount(int accountId)
        {
            var client = new MainServiceSilverlightClient();
            client.EraseAccountCompleted += ClientEraseAccountCompleted;
            client.EraseAccountAsync(accountId);
        }

        #endregion

        #region Webservice completeness events for asynchronous calls

        /// <summary>
        /// Evento para la llamada de insertar cuenta.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public void ClientInsertNewAccountCompleted(object sender, InsertNewAccountCompletedEventArgs e)
        {
            try
            {
                if (e.Error != null)
                {
                    _dialogWindow.Close();
                    _dialogWindow = new CustomChildWindow("Se produjo un error al insertar cuenta","Se produjo un error a la hora de insertar la cuenta, por favor contacte a su administrador");
                    _dialogWindow.Show();
                    return;
                }
                if (e.Result)
                    GetAccountCatalog();
                else
                {
                    _dialogWindow.Close();
                    _dialogWindow = new CustomChildWindow("Se produjo un error al insertar cuenta", "La cuenta no se pudo insertar en la base");
                    _dialogWindow.Show();
                }
                
            }
            catch (Exception exception)
            {
                _dialogWindow = new CustomChildWindow("", exception.Message);
                _dialogWindow.Show();
            }
        }


        /// <summary>
        /// Evento para la llamada de editar cuenta.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public void ClientChangeAccountInformationCompleted(object sender, ChangeAccountInformationCompletedEventArgs e)
        {
            try
            {
                if (e.Error != null)
                {
                    _dialogWindow.Close();
                    _dialogWindow = new CustomChildWindow("Se produjo un error al editar la cuenta","Se produjo un error a la hora de editar la cuenta, por favor contacte a su administrador");
                    _dialogWindow.Show();
                    return;
                }
                if (e.Result)
                    GetAccountCatalog();
                else
                {
                    _dialogWindow.Close();
                    _dialogWindow = new CustomChildWindow("Se produjo un error al editar la cuenta", "La cuenta no se pudo editar");
                    _dialogWindow.Show();
                }
            }
            catch (Exception exception)
            {
                _dialogWindow = new CustomChildWindow("", exception.Message);
                _dialogWindow.Show();
            }
        }



        /// <summary>
        /// Evento para la llamada de borrar cuenta
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ClientEraseAccountCompleted(object sender, EraseAccountCompletedEventArgs e)
        {
            try
            {
                if (e.Error != null)
                {
                    _dialogWindow.Close();
                    _dialogWindow = new CustomChildWindow("Error al eliminar cuenta", "Se produjo un error al intentar conectarse con el servidor, por favor intente nuevamente");
                    _dialogWindow.Show();
                }
                else if (e.Result)
                {
                    GetAccountCatalog();
                }
                else
                {
                    _dialogWindow.Close();
                    _dialogWindow = new CustomChildWindow("Error al eliminar cuenta", "No se pudo borrar la cuenta, verifique si esta no tiene movimientos asociados, de lo contrario no se podrá borrar");
                    _dialogWindow.Show();
                }
            }
            catch (Exception exception)
            {
                _dialogWindow = new CustomChildWindow("",exception.Message);
                _dialogWindow.Show();
            }
        }

        /// <summary>
        /// Evento para la llamada de obtener catalogo.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public void ClientGetAccountingCatalogCompleted(object sender, GetAccountingCatalogCompletedEventArgs e)
        {
            try
            {
                if (e.Error != null)
                {
                    _dialogWindow.Close();
                    _dialogWindow = new CustomChildWindow("Error al obtener el Catálogo Contable","Se produjo un error no esperado, por favor intentelo mas tarde");
                    _dialogWindow.Show();
                    return;
                }
                if (e.Result == null)
                {
                    _dialogWindow.Close();
                    _dialogWindow = new CustomChildWindow("No se encontraron Catálogos", "El Servidor no devolvió ningun Catálogo Contable, por favor cree uno");
                    _dialogWindow.Show();
                    return;
                }

                _dialogWindow.Close();
                _dialogWindow = new CustomChildWindow("Operación exitosa.", "La petición ha sido procesada correctamente.");
                _dialogWindow.Show();
                _authenticatedUserManager.OnlineUser.Company.AccountCatalog = e.Result;
                Reset();
            }
            catch (Exception exception)
            {
                _dialogWindow = new CustomChildWindow("",exception.Message);
                _dialogWindow.Show();
            }
        }
        #endregion

        #region Auxiliares
        /// <summary>
        /// Obtiene un color a partir de un hexadecimal
        /// </summary>
        /// <param name="s"></param>
        /// <returns></returns>
        public Color GetColorFromHexString(string s)
        {
            byte a = Convert.ToByte(s.Substring(0, 2), 16);
            byte r = Convert.ToByte(s.Substring(2, 2), 16);
            byte g = Convert.ToByte(s.Substring(4, 2), 16);
            byte b = Convert.ToByte(s.Substring(6, 2), 16);
            return Color.FromArgb(a, r, g, b);
        }


        #endregion
    }
}
